_helpers.ts 1.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051
  1. import { NextResponse } from "next/server";
  2. import type { Database } from "@/types/database";
  3. type MovieRow = Database["public"]["Tables"]["movies"]["Row"];
  4. type MovieAccessResult =
  5. | { ok: true; userId: string; movie: Pick<MovieRow, "id" | "group_id"> }
  6. | { ok: false; response: NextResponse };
  7. export async function verifyMovieAccess(
  8. // Supabase v2 generics resolve movies table to `never`; typed client param breaks downstream queries
  9. // eslint-disable-next-line @typescript-eslint/no-explicit-any
  10. supabase: any,
  11. movieId: string,
  12. ): Promise<MovieAccessResult> {
  13. const {
  14. data: { user },
  15. } = await supabase.auth.getUser();
  16. if (!user) {
  17. return { ok: false, response: NextResponse.json({ error: "Unauthorized" }, { status: 401 }) };
  18. }
  19. const { data: movie, error: fetchError } = await supabase
  20. .from("movies")
  21. .select("id, group_id")
  22. .eq("id", movieId)
  23. .single();
  24. if (fetchError || !movie) {
  25. return {
  26. ok: false,
  27. response: NextResponse.json({ error: "Movie not found" }, { status: 404 }),
  28. };
  29. }
  30. const { data: membership } = await supabase
  31. .from("group_members")
  32. .select("user_id")
  33. .eq("group_id", movie.group_id)
  34. .eq("user_id", user.id)
  35. .single();
  36. if (!membership) {
  37. return {
  38. ok: false,
  39. response: NextResponse.json({ error: "Not a group member" }, { status: 403 }),
  40. };
  41. }
  42. return { ok: true, userId: user.id, movie };
  43. }